home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 7
/
Apprentice-Release7.iso
/
Source Code
/
Pascal
/
Snippets
/
Event speed
/
Event speed.p
< prev
next >
Wrap
Text File
|
1997-01-21
|
7KB
|
237 lines
{Event processing speed test}
{By Ingemar Ragnemalm 1997}
{Many game programmers claim that you should not process events at all, not even with GetOSEvent,}
{because it is too slow. Others claim that you should always use WaitNextEvent no matter what.}
{}
{I say that both are wrong. GetOSEvent is very fast. WaitNextEvent is not, not even when quitting all}
{other applications except Finder, and quitting the Finder is no good habit IMHO. Reading the keyboard}
{with GetKeys is fast, but hopelessly incompatible with other keyboard layouts than your own. There}
{is a workaround, but few use it.}
{}
{This application is an experiment, to find out the truth. You can select any of four methods,}
{GetNextEvent, WaitNextEvent( with a sleep time of zero), GetOSEvent and None (which uses Button}
{and GetKeys).}
{}
{In my experiments, GetOSEvent had no significant disadvantage to Button/GetKeys. It even was}
{a fair bit faster in many tests! Feel free to draw conclusions, and to hunt down any mistakes I may}
{have made. This was a quick hack, and sure I may have overlooked something – but I kind of doubt it.}
program EventSpeed;
uses
{$ifc UNDEFINED THINK_PASCAL}
Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile,{}
GestaltEqu, Files, Errors, Devices, QuickDrawText,
{$elsec}
InterfacesUI,
{$endc}
MyFakeAlert;
var
myEvent: EventRecord;
w, whichWindow: WindowPtr;
appleMenu, fileMenu: MenuHandle;
gDone: Boolean;
eventMode: Integer;
const
useGNE = 1;
useWNE = 2;
useGOE = 3;
useNone = 4;
procedure SynchMenus;
begin
CheckItem(fileMenu, useGNE, eventMode = useGNE);
CheckItem(fileMenu, useWNE, eventMode = useWNE);
CheckItem(fileMenu, useGOE, eventMode = useGOE);
CheckItem(fileMenu, useNone, eventMode = useNone);
end; {SynchMenus}
procedure SetupMenus;
begin
appleMenu := NewMenu(128, stringof(char($14)));
AppendMenu(appleMenu, 'About Event processing speed test…;(-');
AppendResMenu(appleMenu, 'DRVR');
InsertMenu(appleMenu, 0); { put apple menu at end of menu bar }
fileMenu := NewMenu(129, 'File');
AppendMenu(fileMenu, 'GetNextEvent/G;WaitNextEvent/W;GetOSEvent/O;None/N;(-;Quit/Q');
InsertMenu(fileMenu, 0); { put file menu at end of menu bar }
DrawMenuBar;
SynchMenus;
end; {SetupMenus}
procedure MenuSelection (theSelection: Longint);
var
name: Str255;
saveport: GrafPtr;
begin
case HiWord(theSelection) of
128:
begin
if LoWord(theSelection) = 1 then
ReportStr('Experimental program. Why are game programmers so scared of GetOSEvent?')
else
begin
GetPort(saveport);
GetMenuItemText(appleMenu, 1, name); (* get name *)
if OpenDeskAcc(name) = 0 then (* run the desk accessory *)
;
SetPort(saveport);
end;
end;
129:
case LoWord(theSelection) of
useGNE, useWNE, useGOE, useNone:
eventMode := LoWord(theSelection);
otherwise
gDone := true;
end; {case MenuSelect}
otherwise
end;
SynchMenus;
HiLiteMenu(0);
end; {MenuSelection}
procedure HandleEvents;
var
hasEvent: Boolean;
theKey: Char;
whichPart: Integer;
theSelection: Longint;
myKeyMap: KeyMap;
begin
case eventMode of
useGNE:
begin
{GetNextEvent is the old event processing method.}
SystemTask;
hasEvent := GetNextEvent(everyEvent, myEvent);
end;
useWNE:
{WaitNextEvent is the new event processing method, recommended by Apple.}
{The wait time is set to zero to get maximum performance (which also means that it is very unfriendly to}
{other processes). It should NOT use zero if switched to the background - if it processes background events}
{at all!}
hasEvent := WaitNextEvent(everyEvent, myEvent, 0, nil);
useGOE:
{GetOSEvent is an low-level event processing method that doesn't give time to other processes at all.}
{It is therefore very fast, but many newbie game programmers don't dare using it anyway. I think they should.}
hasEvent := GetOSEvent(everyEvent, myEvent); {or perhaps mDownMask + updateMask + keyDownMask}
useNone:
begin
hasEvent := false;
{When Button is down, get an event the usual way. This means that menus are suppirted, but command-key}
{equivalents are not. Button and GetKeys is what many games use.}
if Button then
hasEvent := WaitNextEvent(everyEvent, myEvent, 0, nil)
else
begin
GetKeys(myKeyMap);
if myKeyMap[12] and myKeyMap[55] then
gDone := true; {Command-Q?}
{Here we could find if command-Q is pressed etc. Rather tedious compared to doing it with events, and}
{you can't be sure that all keyboards follow your layout! (Most special keys don't, like "+" and "-".)}
{If you must use GetKeys, you should use KeyTrans/KeyTranslate.}
end;
end;
otherwise
begin
SysBeep(1);
hasEvent := WaitNextEvent(everyEvent, myEvent, 0, nil);
end;
end; {case}
if hasEvent then
case myEvent.what of
updateEvt:
if WindowPtr(myEvent.message) = w then
begin
BeginUpdate(w);
{Draw here!}
PaintRect(w^.portRect);
EndUpdate(w);
end;
keyDown:
begin
theKey := char(BitAnd(myEvent.message, charCodeMask));
if (BitAnd(myEvent.modifiers, cmdKey) <> 0) then
MenuSelection(MenuKey(theKey))
else
{DoKey(theKey, theEvent.modifiers)}
;
end;
mouseDown:
begin
whichPart := FindWindow(myEvent.where, whichWindow);
case whichPart of
inMenuBar:
begin
theSelection := MenuSelect(myEvent.where);
MenuSelection(theSelection);
end;
inSysWindow:
SystemClick(myEvent, whichWindow);
inContent:
begin
end;
otherwise
end; {case whichPart}
end;
otherwise
end;{case myEvent.what}
end; {HandleEvents}
var
i, j: Integer;
pat: PixPatHandle;
numLoops: Longint;
startTicks: Longint;
drawRect: Rect;
begin
{CodeWarrior needs inits here}
{$IFC UNDEFINED THINK_PASCAL}
{ Initialize all the needed managers. }
InitGraf(@qd.thePort);
InitFonts;
InitWindows;
InitMenus;
TEInit;
InitDialogs(nil);
MaxApplZone;
{$ENDC}
w := GetNewCWindow(128, nil, WindowPtr(-1));
pat := GetPixPat(128);
SetPort(w);
PenPixPat(pat);
eventMode := useGNE;
SetupMenus;
InitCursor;
numLoops := 0;
SetRect(drawRect, 0, 0, 150, 30);
startTicks := TickCount;
repeat
HandleEvents;
numLoops := numLoops + 1;
{After 60 ticks have passed, print out the number of loops!}
if startTicks + 60 <= TickCount then
begin
EraseRect(drawRect);
MoveTo(4, 20);
DrawString(StringOf(numLoops : 1, ' loops/sec'));
startTicks := TickCount;
numLoops := 0;
end;
until gDone;
end.